import mpld3
from mpld3 import plugins
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.font_manager import FontProperties

class RackManager:
    def __init__(self, default_height=44):
        self.racks = {}
        self.default_height = default_height
        self.rack_rows = {}  # 存储机柜所在行数
    
    def init_rack(self, name, height=None, row=1):
        height = height if height else self.default_height
        self.racks[name] = (
            pd.DataFrame(
                columns=['设备名称','序列号','起始U位','设备高度','设备状态'],
                index=pd.Index([], name='机柜位置')
            ),
            height
        )
        self.rack_rows[name] = row  # 记录机柜所在行
        return self.racks[name]
    
    def add_device(self, rack_name, name, sn, start_u, height, status='normal'):
        rack_df, rack_height = self.racks[rack_name]
        if start_u + height > rack_height + 1:
            raise ValueError(f"设备超出机柜{rack_name}的U位范围")
        display_name = f"[{status.upper()}] {name}"    
        new_row = pd.DataFrame([[display_name, sn, start_u, height, status]],
                             columns=rack_df.columns)
        self.racks[rack_name] = (
            pd.concat([rack_df, new_row], ignore_index=True),
            rack_height
        )
        return self.racks[rack_name]
    
    def visualize_racks(self, fig_width=50,rack_width=1.5):
        total_racks = len(self.racks)
        max_rack_height = max(height for _, height in self.racks.values())
        max_rows = max(self.rack_rows.values()) if self.rack_rows else 1
        fig_height = max_rack_height // 2 * max_rows
        
        plt.figure(figsize=(fig_width, fig_height), dpi=120)
        ax = plt.gca()
        
        status_colors = {
            'normal': ('#4CAF50', '#2E7D32'),
            'warning': ('#FFC107', '#FF8F00'),
            'error': ('#F44336', '#C62828'),
            'offline': ('#9E9E9E', '#616161')
        }
        
        font = FontProperties(fname='simhei.ttf', size=18, weight='bold')
        title_font = FontProperties(fname='simhei.ttf', size=24, weight='bold')
        u_font = FontProperties(fname='simhei.ttf', size=14)
        
        # 按行分组机柜
        row_groups = {}
        for rack_name, row in self.rack_rows.items():
            if row not in row_groups:
                row_groups[row] = []
            row_groups[row].append(rack_name)
        
        # 计算每行最多机柜数
        max_racks_per_row = max(len(racks) for racks in row_groups.values())
        
        for row_num, rack_names in row_groups.items():
            ax.text(-0.5,  # x坐标位置
               (max_rows - row_num) * (max_rack_height + 10) + max_rack_height + 5,  # 倒序计算y坐标
               f"机房第 {row_num} 排",
               fontproperties=FontProperties(fname='simhei.ttf', size=32, weight='bold'),
               color='#0D47A1',
               va='bottom',
               ha='left',
               bbox=dict(facecolor='white', alpha=0.9,
                        boxstyle='round,pad=0.8',
                        edgecolor='#BBDEFB',
                        linewidth=2))
            
            for col, rack_name in enumerate(rack_names):
                rack_df, rack_height = self.racks[rack_name]
                rack_pos_x = col * (rack_width + 0.5)  # 根据宽度调整间距
                rack_pos_y = (max_rows - row_num) * (max_rack_height + 10)
                # 绘制U位
                for u in range(1, rack_height + 1):
                    ax.add_patch(Rectangle(
                       (rack_pos_x, rack_pos_y + u), 
                       rack_width, 1,  # 使用参数化宽度
                       facecolor='black', edgecolor='#BDBDBD', linewidth=1.8
                       ))
                    ax.text(rack_pos_x+0.5, rack_pos_y+u+0.5, f"U{u}",
                           ha='center', va='center', fontproperties=u_font,
                           color='white')
                # 绘制设备
                for _, row_data in rack_df.iterrows():
                    status = row_data.get('设备状态', 'normal')
                    facecolor, edgecolor = status_colors.get(status, ('#42A5F5', '#1565C0'))
                    ax.add_patch(Rectangle(
                      (rack_pos_x + rack_width*0.05,  # 动态计算边距
                      rack_pos_y + row_data['起始U位']), 
                      rack_width*0.9,  # 设备宽度与机柜宽度比例适配
                      row_data['设备高度'],
                      facecolor=facecolor, 
                      edgecolor=edgecolor, 
                      linewidth=2.5
                     ))
                    device_text = f"{row_data['设备名称']}\n位置:{row_data['起始U位']}-{row_data['起始U位']+row_data['设备高度']-1}\n高度:{row_data['设备高度']}"
                    ax.text(rack_pos_x+0.5, 
                           rack_pos_y + row_data['起始U位']+row_data['设备高度']/2,
                           device_text,
                           ha='center', va='center', 
                           fontproperties=FontProperties(fname='simhei.ttf', size=16),
                           color='white',
                           bbox=dict(boxstyle='round,pad=0.2',
                                     facecolor=(0,0,0,0.3),
                                     edgecolor='none'))
                ax.text(rack_pos_x+0.5, rack_pos_y + rack_height + 3, rack_name,
                       ha='center', fontproperties=title_font,
                       color='#0D47A1')

        plt.title(f"数据中心机柜布局图 (标准高度:{self.default_height}U,机房{row}排)", 
                 fontproperties=title_font, pad=25, color='#1A237E')
        plt.xlim(-1, max_racks_per_row*2.0)
        plt.ylim(0, (max_rack_height + 10) * max_rows)
        plt.axis('off')
        plt.tight_layout()
        plt.savefig('1.png', dpi=300, bbox_inches='tight')
        plt.show()
    
    # 保存为HTML
if __name__ == "__main__":
    manager = RackManager(default_height=40)
    # 初始化机柜时指定所在行数
    manager.init_rack("网络机柜A", row=1)
    manager.init_rack("存储机柜B", row=1)
    manager.init_rack("存储机柜c", row=1,height=30)
    manager.init_rack("存储机柜d", row=1)
    manager.init_rack("存储机柜e", row=1)
    manager.init_rack("存储机柜f", row=1)
    manager.init_rack("服务器机柜A", row=2)
    manager.init_rack("服务器机柜V", row=2)
    
    # 添加设备...
    manager.add_device("网络机柜A", "防火墙", "FW-001", 1, 4, 'normal')
    manager.add_device("网络机柜A", "防火墙", "FW-001", 5, 4, 'normal')
    manager.add_device("网络机柜A", "防火墙", "FW-001", 9, 1, 'normal')
    manager.add_device("网络机柜A", "防火墙", "FW-001", 10, 1, 'normal')
    manager.add_device("网络机柜A", "交换机", "SW-001", 25, 12, 'warning')
    manager.add_device("网络机柜A", "交换机", "SW-001", 37, 1, 'warning')
    manager.add_device("存储机柜B", "磁盘阵列", "DSK-001", 10, 4, 'normal')
    manager.add_device("存储机柜B", "备份服务器", "BAK-001", 20, 2, 'error')
    manager.add_device("存储机柜B", "备份服务器", "BAK-001", 20, 2, 'error')
    manager.add_device("存储机柜B", "备份服务器", "BAK-001", 30, 2, 'error')
    manager.add_device("存储机柜B", "备份服务器", "BAK-001", 32, 4, 'error')
    manager.add_device("存储机柜B", "备份服务器", "BAK-001", 36, 2, 'error')
    manager.add_device("服务器机柜V", "备份服务器", "BAK-001", 36, 1, 'error')
    manager.visualize_racks()

